package csvm_v2;

import csvm_v1.exceptions.WrongCommandFormatException;
import csvm_v2.components.CoinContainer;
import csvm_v2.components.CoinDispenser;
import csvm_v2.components.CoinReceiver;
import csvm_v2.components.DumpFileReader;
import csvm_v2.components.DumpFileWriter;
import csvm_v2.components.ProductContainer;
import csvm_v2.components.ProductDispenser;
import csvm_v2.components.ProductSelector;
import csvm_v2.transaction.Transaction;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * CSVM_V2 adalah kelas bagi vending machine yang telah diperbaiki dari versi
 * pertama, yaitu CSVM_V1 dengan mengubah paradigma menjadi prosedural menjadi
 * berbasis objek
 *
 * @author Muqtafi Akhmad
 */
public class CSVM_V2 {

    /**
     * mengisikan coin receiver
     *
     * @param coinIn coin receiver
     */
    public void setCoinIn(CoinReceiver coinIn) {
        this.coinIn = coinIn;
    }

    /**
     * mengisikan coin stock
     *
     * @param coinStock coin stock
     */
    public void setCoinStock(CoinContainer coinStock) {
        this.coinStock = coinStock;
    }

    /**
     * mengisikan coin dispenser
     *
     * @param coinOut coin dispenser
     */
    public void setCoinOut(CoinDispenser coinOut) {
        this.coinOut = coinOut;
    }

    /**
     * mengisikan produck stock
     *
     * @param productStock product stock
     */
    public void setProductStock(ProductContainer productStock) {
        this.productStock = productStock;
    }

    /**
     * mengisikan product dispenser
     *
     * @param productOut product dispenser
     */
    public void setProductOut(ProductDispenser productOut) {
        this.productOut = productOut;
    }

    /**
     * mengisikan product catalog
     *
     * @param catalog product catalog
     */
    public void setCatalog(ProductSelector catalog) {
        this.catalog = catalog;
    }

    /**
     * mengisikan dump file reader
     *
     * @param reader dump file reader
     */
    public void setReader(DumpFileReader reader) {
        this.reader = reader;
    }

    /**
     * mengisikan dump file writer
     *
     * @param writer dump file writer
     */
    public void setWriter(DumpFileWriter writer) {
        this.writer = writer;
    }

    /**
     * mengembalikan coin receiver
     *
     * @return coin receiver
     */
    public CoinReceiver getCoinIn() {
        return coinIn;
    }

    /**
     * mengemblaikan coin stock
     *
     * @return coin stock
     */
    public CoinContainer getCoinStock() {
        return coinStock;
    }

    /**
     * mengembalikan coin dispenser
     *
     * @return coin dispenser
     */
    public CoinDispenser getCoinOut() {
        return coinOut;
    }

    /**
     * mengembalikan product stock
     *
     * @return product stock
     */
    public ProductContainer getProductStock() {
        return productStock;
    }

    /**
     * mengembalikan product dispenser
     *
     * @return product dispenser
     */
    public ProductDispenser getProductOut() {
        return productOut;
    }

    /**
     * mengembalikan product selector
     *
     * @return product selector
     */
    public ProductSelector getCatalog() {
        return catalog;
    }

    /**
     * mengembalikan dump file reader
     *
     * @return dump file reader
     */
    public DumpFileReader getReader() {
        return reader;
    }

    /**
     * mengembalikan dump file writer
     *
     * @return dump file writer
     */
    public DumpFileWriter getWriter() {
        return writer;
    }

    /**
     * menginisiasi vending machine
     */
    public void initVM() {
        try {
            // membaca dump file
            reader.importDump(filePath);
            // memulai thread untuk komponen vending machine
            catalog_thread.start();
            coinIn_thread.start();
            coinStock_thread.start();
            productStock_thread.start();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(CSVM_V2.class.getName()).log(Level.SEVERE, null, ex);
        } catch (WrongCommandFormatException ex) {
            Logger.getLogger(CSVM_V2.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * menutup vending machine
     */
    public void closeVM() {
        try {
            // menuliskan dump file
            writer.exportDump(filePath);
            // menghentikan thread untuk komponen vending machine
            catalog.done();
            catalog_thread.join();
            coinIn.done();
            coinIn_thread.join();
            coinStock.done();
            coinStock_thread.join();
            productStock.done();
            productStock_thread.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(CSVM_V2.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /**
     * coin receiver
     */
    private CoinReceiver coinIn;
    private Thread coinIn_thread;
    /**
     * coin stock
     */
    private CoinContainer coinStock;
    private Thread coinStock_thread;
    /**
     * coin dispenser
     */
    private CoinDispenser coinOut;
    /**
     * product stock
     */
    private ProductContainer productStock;
    private Thread productStock_thread;
    /**
     * product dispenser
     */
    private ProductDispenser productOut;
    /**
     * product selector
     */
    private ProductSelector catalog;
    private Thread catalog_thread;
    /**
     * dump file reader
     */
    private DumpFileReader reader;
    /**
     * dump file writer
     */
    private DumpFileWriter writer;
    /**
     * file path ke dump file
     */
    private String filePath;

    /**
     * konstruktor dari CSVM_V2
     *
     * @param filePath path ke dump file
     */
    public CSVM_V2(String filePath) {
        this.filePath = filePath;
        coinIn = new CoinReceiver();
        coinIn_thread = new Thread(coinIn);
        coinStock = new CoinContainer();
        coinStock_thread = new Thread(coinStock);
        coinOut = new CoinDispenser(coinStock);
        productStock = new ProductContainer();
        productStock_thread = new Thread(productStock);
        productOut = new ProductDispenser();
        catalog = new ProductSelector();
        catalog_thread = new Thread(catalog);
        reader = new DumpFileReader(coinStock, productStock, catalog);
        writer = new DumpFileWriter(coinStock, productStock, catalog);
    }

    /**
     * memulai kerja dari vending machine, mengulang transaksi hingga pengguna
     * mengetikkan exit
     */
    public void start() {
        String command;
        Scanner in = new Scanner(System.in);
        // menginisiasi vending machine
        initVM();
        System.out.println("Masukkan 'buy' untuk membeli product dan 'exit' untuk keluar program");
        command = in.nextLine();
        while (!command.equals("exit")) {
            if (command.equals("buy")) {
                try {
                    // melakukan transaksi, memulai sebuah session Transaction
                    Thread transactionThread = new Thread(new Transaction(this));
                    transactionThread.start();
                    transactionThread.join();
                } catch (InterruptedException ex) {
                    Logger.getLogger(CSVM_V2.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else {
                System.out.println("unknown command : " + command);
            }
            System.out.println("Masukkan 'buy' untuk membeli product dan 'exit' untuk keluar program");
            command = in.nextLine();
        }
        // menutup vending machine
        closeVM();
    }

    /**
     * method utama dari project, menginstansiasi sebuah vending machine
     * kemudian memulai vending machine untuk bekerja
     *
     * @param args
     */
    public static void main(String[] args) {
        CSVM_V2 vendingMachine = new CSVM_V2("vm_dump.txt");
        vendingMachine.start();
    }
}
